<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
    <title>SOAPI-EXPLORE Beta</title>
    <link href="3rd-party/jquery-ui-1.8.2.custom.css" rel="stylesheet" type="text/css" />
    
    
    <style type="text/css">
        /* General styles */body {
            margin: 0;
            padding: 0;
            border: 0; /* This removes the border around the viewport in old versions of IE */
            width: 100%;
            background: #fff;
            min-width: 600px; /* Minimum width of layout - remove line if not required */ /* The min-width property does not work in old versions of Internet Explorer */
            font-size: 90%;
            font-family: Sans-Serif;
        }
        /* Header styles */#header {
            clear: both;
            float: left;
            width: 100%;
        }
        #header {
            border-bottom: 1px solid #000;
        }
        /* 'widths' sub menu */.sub-header {
            clear: both;
            background: #eee;
            border-top: 1px solid #000;
            margin: 0;
            padding: 6px 15px !important;
            text-align: left;
        }
        /* column container */.colmask {
            position: relative; /* This fixes the IE7 overflow hidden bug and stops the layout jumping out of place */
            clear: both;
            float: left;
            width: 100%; /* width of whole page */
            overflow: hidden; /* This chops off any overhanging divs */
        }
        /* 2 column left menu settings */.leftmenu {
            background: #EEE;
        }
        .leftmenu .colright {
            float: left;
            width: 200%;
            position: relative;
            left: 300px;
            background: #fff;
        }
        .leftmenu .col1wrap {
            float: right;
            width: 50%;
            position: relative;
            right: 280px;
            padding-bottom: 1em;
        }
        .leftmenu .col1 {
            margin: 0 20px 0 280px;
            position: relative;
            right: 100%;
            overflow: hidden;
        }
        .leftmenu .col2 {
            float: left;
            width: 290px;
            position: relative;
            right: 290px;
            height: 500px;
            overflow-x: hidden;
            overflow-y: scroll;
            font-size: 7pt;
        }
        /* Footer styles */#footer {
            clear: both;
            float: left;
            width: 100%;
            border-top: 1px solid #000;
        }
        #footer p {
            padding: 10px;
            margin: 0;
            font-size: 8pt;
        }
        .ui-datepicker {
            font-size: 7pt;
        }
        #api-version {
            font-size: 8pt;
        }
        #json-output {
            font-family: Consolas, "Andale Mono WT" , "Andale Mono" , "Lucida Console" , "Lucida Sans Typewriter" , "DejaVu Sans Mono" , "Bitstream Vera Sans Mono" , "Liberation Mono" , "Nimbus Mono L" , Monaco, "Courier New" , Courier, monospace;
            position: relative;
            border: solid 1px silver;
            margin: 2px;
            width: 100%;
            height: 500px;
            font-size: 8pt;
            overflow: auto;
            white-space: pre;
        }
        .route-summary {
            font-size: 7pt;
            border-bottom: solid 1px black;
            margin-bottom: 4px;
        }
        .submit {
            margin-left: 180px;
        }
        .route-header {
            font-weight: bold;
        }
    </style>
    <!--[if lt IE 7]>
    <style media="screen" type="text/css">
    .col1 {
	    width:100%;
	}
    </style>
    <![endif]-->

    <script src="3rd-party/json2.js" type="text/javascript"></script>

    <script src="3rd-party/jquery-1.4.1.js" type="text/javascript"></script>

    <script src="3rd-party/jquery-ui-1.8.2.custom.min.js" type="text/javascript"></script>

    <script type="text/javascript">

        // 
        // Soapi-Explore
        // http://soapi.info/
        // 
        // Copyright 2010, Sky Sanders
        // Dual licensed under the MIT or GPL Version 2 licenses.
        // http://soapi.info/code/js/license.aspx
        // 
        // Date: Thu July 01 2010
        //     


        $(document).ready(function() {

            var apiKey = 'NLIXkFCt8Eu-oq1Mzw3pgg';

            jQuery.fn.ForceNumericOnly = function(integer) {
                return this.each(function() {
                    $(this).keydown(function(e) {
                        var key = e.charCode || e.keyCode || 0;
                        return ((key == 110 && !integer) || key == 8 || key == 9 || key == 46 || (key >= 37 && key <= 40) || (key >= 48 && key <= 57) || (key >= 96 && key <= 105));
                    })
                })
            };

            function initializeExplorer(api) {

                $('#api-version').text('API version ' + api.Version + ' ' + api.Revision);
                $('#api-comment').text(api.Comment);

                $.each(api.Routes, function(idx, route) {
                    buildControl(api, route);
                });

                $(".datepicker").datepicker();
                $(".numeric").ForceNumericOnly();
                $(".integer").ForceNumericOnly(true);

                $(".submit").click(function() {
                    var self = $(this);
                    var inputTable = self.parent().find("TABLE");

                    // validate input                
                    var valid = true;
                    $(inputTable).find(".required").each(function(idx, itm) {
                        var input = $(itm);
                        if (!input.val()) {
                            input.hide().fadeIn(200).focus();
                            valid = false;
                        }
                    });

                    $(inputTable).find(".datepicker").each(function(idx, itm) {
                        var input = $(itm);
                        if (input.val() && isNaN(new Date(input.val()))) {
                            input.hide().fadeIn(200).focus();
                            valid = false;
                        }
                    });

                    if (!valid) {
                        return;
                    }


                    // build url

                    var path = "/" + api.Version + inputTable.data("path");
                    var params = $(inputTable).find(".parameter");
                    var first = true;
                    params.each(function(idx, itm) {
                        var param = $(itm);
                        var paramVal = param.val();
                        if (paramVal) {
                            var paramName = param.attr('name');

                            if (param.hasClass('datepicker')) {
                                paramVal = Math.round(new Date(paramVal).getTime() / 1000);
                            }
                            var token = "{" + paramName + "}";
                            if (path.indexOf(token) > -1) {
                                path = path.replace(token, encodeURIComponent(paramVal));
                            }
                            else {
                                if (param.attr('type') == 'checkbox') {
                                    if (param.is(':checked')) {
                                        paramVal = 'true';
                                    }
                                    else {
                                        paramVal = null;
                                    }
                                }
                                if (param.attr('type') == 'enum' && param[0].selectedIndex == 0) {
                                    paramVal = null;
                                }
                                if (paramVal) {
                                    path = path + (first ? "?" : "&") + paramName + "=" + encodeURIComponent(paramVal);
                                    first = false;
                                }
                            }
                        }
                    });



                    var url = "http://" + $("#target-site").val() + path;

                    $('#path').html(url);
                    $('#path').attr('href', url);

                    $('#json-output').text("loading...");
                    $.getJSON(url + (first ? "?" : "&") + "key=" + apiKey + "&jsonp=?", function(data) {
                        $('#json-output').text(JSON.stringify(data, null, " "));
                    });


                });

                $("#route-container").accordion({ autoHeight: false });

                $('.route-container .head').click(function() {
                    $(this).next().toggle();
                    return false;
                }).next().hide();
            }


            function buildControl(api, route) {



                $('#route-container').append('<h3><a class="route-header" href="#">' + route.Path + '</a></h3>');
                var content = $('<div></div>').addClass('route-content').css('overflow', 'hidden');
                var summary = $('<div></div>').addClass('route-summary').text(route.Summary);
                content.append(summary);
                var inputTable = $("<table/>").attr('id', route.RouteName + '-input');
                inputTable.data('path', route.Path);
                content.append(inputTable);


                // this map is used to help organize parameters
                // in a logical order. unknown parameters are appended
                var paramMap = {
                    "id": false,
                    "toid": false,
                    "intitle": false,
                    "filter": false,
                    "revisionguid": false,
                    "tags": false,
                    "tagged": false,
                    "nottagged": false,
                    "body": false,
                    "answers": false,
                    "comments": false,
                    "sort": false,
                    "min": false,
                    "max": false,
                    "order": false,
                    "pagesize": false,
                    "page": false,
                    "fromdate": false,
                    "todate": false
                };

                $.each(route.Parameters, function(idx, parameter) {
                    paramMap[parameter.Name] = parameter;
                });

                var sortedParams = [];

                for (var pname in paramMap) {
                    if (paramMap.hasOwnProperty(pname)) {
                        sortedParams.push(paramMap[pname]);
                    }
                }


                $.each(sortedParams, function(idx, parameter) {
                    if (parameter) {



                        var inputRow = $("<tr/>");
                        inputTable.append(inputRow);
                        var name = $("<td/>").css('text-align', 'right');
                        if (!parameter.Optional) {
                            name.css('font-weight', 'bold');
                        }
                        name.text(parameter.Name + ": ");
                        inputRow.append(name);

                        var control = $("<td/>").css('text-align', 'left');
                        inputRow.append(control);
                        inputRow.attr('title', (parameter.Optional ? "Optional: " : "Required: ") + parameter.Summary + " " + parameter.TypeDescription);



                        switch (parameter.TypeDescription) {
                            case "128-bit floating point, IEEE 754":
                                input = $('<input type="text"  class="numeric"/>');
                                break;
                            case "32-bit integer, range [0, 2,147,483,647]":
                            case "32-bit integer, range [1, 2,147,483,647]":
                            case "32-bit integer, range [0, 100]":
                            case "32-bit signed integer":
                                input = $('<input type="text" class="integer"/>');
                                break;

                            case "array of string":
                                input = $('<input type="text" />');
                                break;

                            case "boolean":
                                input = $('<input type="checkbox" >');
                                break;

                            case "guid, 8-4-4-4-12 format":
                                input = $('<input type="text" />');
                                break;

                            case "string":
                                input = $('<input type="text" class=" "/>');
                                break;

                            case "unix epoch date, range [0, 253,402,300,799]":
                                if (parameter.Name != "min" && parameter.Name != "max") {
                                    input = $('<input type="text" class="datepicker"/>');
                                }
                                else {
                                    //TODO: pay attention to api changes, this is a compensation for faulty API specs
                                    input = $('<input type="text" class=" "/>');
                                }


                                break;
                            default:
                                // check for enum
                                if (parameter.Values.length != 0) {
                                    input = $('<select type="enum"/>');
                                    $.each(parameter.Values, function(idx, value) {
                                        input.append($("<option></option>").attr("value", value).text(value));
                                    });
                                }
                                else {
                                    // default to text box
                                    input = $('<input type="text" />');
                                }
                                break;
                        }

                        input.addClass("parameter");
                        if (!parameter.Optional) {
                            input.addClass("required");
                        }

                        input.attr('name', parameter.Name);

                        control.append(input);
                    }
                });

                content.append("<input type='button' value='submit' class='submit'/>");
                content.appendTo('#route-container');
            }

            function initializeSiteList(data) {
                var el = $("select#target-site")[0];
                el.options.length = 0;

                $.each(data, function() {
                    el.options[el.options.length] = new Option(this.display_name, this.api_path);
                });

            }
            $.getJSON("http://soapi.info/rest/map?jsonp=?", initializeSiteList);
            $.getJSON("http://soapi.info/rest/api?format=json&jsonp=?", initializeExplorer);

        });


    </script>

</head>
<body>
    <div id="header">
        <h3>
            SOAPI-EXPLORE <span id='api-version'></span>
        </h3>
        <p>
            A self-updating StackOverflow API test harness - SOAPI-EXPLORE is self contained
            and may be saved/run locally</p>
        <p class="sub-header">
            <select id="target-site">
            </select>
            <a href="" target="_blank" id="path"></a>
        </p>
    </div>
    <div class="colmask leftmenu">
        <div class="colright">
            <div class="col1wrap">
                <div class="col1">
                    <pre id="json-output">output</pre>
                </div>
            </div>
            <div class="col2" id="route-container">
            </div>
        </div>
    </div>
    <div id="footer">
        <p>
            SOAPI-EXPLORE &copy; 2010 Sky Sanders - this program is licensed under GPLv2 and
            MIT licenses &nbsp;&nbsp;&nbsp;<a href="http://soapi.info/tools/explore">updates and
                info</a></p>
        <strong>TODO:</strong>
        <ul>
            <li>Sort/group parameters</li>
            <li>Fix IE7 pre rendering issue</li>
            <li>Add range validation</li>
        </ul>
    </div>
</body>
</html>
